import {
    _decorator,
    AudioSource,
    Color,
    Component,
    EventTouch,
    instantiate,
    Label,
    log,
    Node,
    Prefab,
    Sprite,
    SpriteFrame,
    TiledLayer,
    Vec2
} from 'cc';
import { GRID_SIZE } from './Const';
import { Tile } from './Tile';
import { gameOver } from './gameOver';
const { ccclass, property } = _decorator;

@ccclass('Controller')
export class Controller extends Component {

    /**
     * 滑动监听参数，如果是false，则不进行滑动操作
     */
    private touchbegin: boolean = false;
    /**
     * 滑动距离，只有滑动大于这个距离才判断为滑动了
     */
    private touchDistance: number = 50;

    //分数文本
    @property(Label)
    scoreLabel: Label = null;
    //最高分文本
    @property(Label)
    bestLabel: Label = null;
    ///滑动节点，只有在这个节点范围内的滑动才有效
    @property(Node)
    touch: Node = null;
    //瓦片父类
    @property(Node)
    grid: Node = null;
    //瓦片预制体
    @property(Prefab)
    tilePrefab: Prefab = null;
    //结算预制体
    @property(Prefab)
    gameover: Prefab = null;
    //结算预制体放置的节点
    @property(Node)
    parentNode: Node = null;
    // //全局音效
    // @property(AudioSource)
    // audio: AudioSource = null;

    //瓦片值,类型为number的二维数组，用来存储所有的瓦片的位置
    private tileValue: number[][] = [];

    //类型为node的二维数组，用来存储所有的瓦片信息
    private tiles: Node[][] = [];
    //当前分数
    private score: number = 0;
    //最高分
    private bestScore: number = 0;

    start() {
        this.reset();
        // this.onEnd()

    }
    /**
     * 重置游戏
     */
    reset() {
        this.cleanGame() //清除游戏格子数据
        this.initData() //初始化数据
        this.setbgTile()    //设置背景格子
        this.initRandonNumber() //开局随机生成两个瓦片
        this.initLiestenr() //初始化监听
        this.updateUI() //更新UI
    }
    /**
     * 清除游戏格子数据
     */
    cleanGame() {
        console.log("清除游戏格子数据");
        this.grid.removeAllChildren();
    }
    /**
     * 初始化数据
     */
    initData() {
        this.scoreLabel.string = "0";
        for (let i = 0; i < GRID_SIZE; i++) {
            //先给二维数组赋值为空,不然之后调用值为undefined
            this.tileValue[i] = [];
            this.tiles[i] = [];
            for (let j = 0; j < GRID_SIZE; j++) {
                this.tileValue[i][j] = 0;
                this.tiles[i][j] = null;

            }

        }

    }
    /**
     * 初始化监听
     * 防止重复监听, 所以需要先解绑再绑定
     */
    initLiestenr() {
        this.touch.off(Node.EventType.TOUCH_START, this.touchStart, this);
        this.touch.off(Node.EventType.TOUCH_MOVE, this.touchMove, this);

        this.touch.on(Node.EventType.TOUCH_START, this.touchStart, this);
        this.touch.on(Node.EventType.TOUCH_MOVE, this.touchMove, this);
    }

    /**
     * 设置背景格子,因为背景格子是空格子，所以value参数是0
     */
    setbgTile() {
        let grid = this.grid;
        for (let i = 0; i < GRID_SIZE; i++) {
            for (let j = 0; j < GRID_SIZE; j++) {
                //拿着i和j去创建瓦片
                this.createTile(0, i, j);
            }

        }
    }

    /**
     * 创建瓦片
     */
    createTile(value: number, x: number, y: number) {
        //创建瓦片
        let tile = instantiate(this.tilePrefab);
        let tileScript = tile.getComponent(Tile)
        //调用瓦片初始化方法，传入值和位置
        tileScript.inittile(value, x, y);
        this.grid.addChild(tile);
        //把瓦片添加到数组中
        this.tiles[x][y] = tile;
        //把瓦片的值添加到数组中
        this.tileValue[x][y] = value;
    }

    /**
     * 初始化，开局随机生成两个数字
     */
    initRandonNumber() {
        for (let i = 0; i < 2; i++) {
            this.randomNumber()
        }

    }

    /**
     * 随机位置生成随机数字的瓦片
     */
    randomNumber() {
        let value = Math.random() > 0.5 ? 2 : 4
        //保存空格子的数组
        let nullgridsList: Vec2[] = []
        //拿到所有空格子
        for (let i = 0; i < GRID_SIZE; i++) {
            for (let j = 0; j < GRID_SIZE; j++) {
                //如果这个格子的值为0，那么就是空格子
                if (this.tileValue[i][j] == 0) {
                    nullgridsList.push(new Vec2(i, j))
                }
            }
        }
        //在数组中随机选一个空格子
        let nullgrid = nullgridsList[Math.floor(Math.random() * nullgridsList.length)]
        //创建格子
        this.createTile(value, nullgrid.x, nullgrid.y)
    }

    /**
     * 触摸开始
     */
    touchStart(event: EventTouch) {
        this.touchbegin = true
    }

    /**
     * 滑动监听，通过滑动开始与结束的坐标绝对值与滑动距离常量做比较，判断是否滑动以及滑动的方向
     * @param event
     */
    touchMove(event: EventTouch) {
        //如果touchbegin为false，则不进行滑动操作
        if (this.touchbegin == false) {
            return;
        }
        //获取滑动开始与结束的坐标的差值
        let delta = event.getLocation().subtract(event.getStartLocation());
        //如果滑动距离的绝对值大于常量，则进行滑动操作
        if (Math.abs(delta.x) > this.touchDistance) {
            if (delta.x > 0) {
                this.moveRight();
            } else {
                this.moveLeft();
            }
            this.touchbegin = false;
        } else if (Math.abs(delta.y) > this.touchDistance) {
            if (delta.y > 0) {
                this.moveUp();
            } else {
                this.moveDown();
            }
            this.touchbegin = false;
        }
        // touchBegin为false, 说明已经触发过滑动, 需要更新UI
        if (this.touchbegin == false) {
            this.updateUI();
            if (this.checkGameOver()) {
                console.log("游戏结束")
                this.onEnd()
            }
        }
    }

    /**
     * 右移方法
     */
    moveRight() {
        //从右往左开始遍历，把每个格子依次右移
        //判断是否有移动，没移动则不生成新的数字
        let hasMove = false
        // 记录需要移动或者合并的位置
        for (let j = 0; j < GRID_SIZE; j++) {
            // 记录需要移动或者合并的位置
            let lastIndex = GRID_SIZE - 1;
            for (let i = GRID_SIZE - 1; i >= 0; i--) {
                //拿到当前的格子的值
                let value = this.tileValue[i][j]
                //如果这个格子的值为0，或者格子在最后一列，则不进行移动操作
                if (value == 0 || i == lastIndex) {
                    continue;
                }
                //如果右边是空格子, 则直接移动过去,如果右边的格子值全都为0，可以直接移动到最后一个空格子
                if (this.tileValue[lastIndex][j] == 0) {
                    this.moveTile(i, j, lastIndex, j);
                    hasMove = true;
                } else {
                    //如果右边的格子值等于当前格子的值，则合并
                    if (this.tileValue[lastIndex][j] == value) {
                        this.mergeTile(i, j, lastIndex, j)
                        lastIndex--;
                        hasMove = true;
                    } else {
                        //判断自己的格子是否是无法合并格子的前一个格子，是则跳出循环并且把lastIndex赋值为i
                        if (lastIndex - 1 == i) {
                            lastIndex = i;
                            continue;
                        }
                        //移动到无法合并格子的前一个格子
                        this.moveTile(i, j, lastIndex - 1, j)
                        lastIndex--
                        hasMove = true
                    }

                }
            }
        }
        //如果有移动则生成新的数字
        if (hasMove) {
            this.randomNumber()
        }

    }
    /**
     * 左移方法
     */
    moveLeft() {
        let hasMove: boolean = false;
        for (let j = 0; j < GRID_SIZE; j++) {
            // 记录需要移动或者合并的位置
            let lastIndex = 0;
            for (let i = 0; i < GRID_SIZE; i++) {
                let value = this.tileValue[i][j];
                // 如果是空格子或者是是同一个位置, 则跳过
                if (value == 0 || i == lastIndex) {
                    continue;
                }
                // 如果是空格子, 则直接移动过去
                if (this.tileValue[lastIndex][j] == 0) {
                    this.moveTile(i, j, lastIndex, j);
                    hasMove = true;
                } else {
                    // 如果是相同的格子, 则合并
                    if (this.tileValue[lastIndex][j] == value) {
                        this.mergeTile(i, j, lastIndex, j);
                        lastIndex++;
                        hasMove = true;
                    } else {
                        // 无法合并, 并且相邻,就无法移动, 需要判定下一个
                        if (lastIndex + 1 == i) {
                            lastIndex = i;
                            continue;
                        }
                        // 移动到下一个空格子
                        this.moveTile(i, j, lastIndex + 1, j);
                        lastIndex++;
                        hasMove = true;
                    }
                }
            }
        }
        // 如果有移动, 则生成新的数字
        if (hasMove) {
            this.randomNumber();
        }
    }
    /**
     * 下移方法
     */
    moveDown() {
        let hasMove = false
        for (let i = 0; i < GRID_SIZE; i++) {
            let lastIndex = 0
            for (let j = 0; j < GRID_SIZE; j++) {
                let value = this.tileValue[i][j]
                //从0开始往后排
                if (value == 0 || j == lastIndex) {
                    continue
                }
                if (this.tileValue[i][lastIndex] == 0) {
                    this.moveTile(i, j, i, lastIndex)
                    hasMove = true
                } else {
                    if (this.tileValue[i][lastIndex] == value) {
                        this.mergeTile(i, j, i, lastIndex)
                        lastIndex++
                        hasMove = true
                    } else {
                        if (lastIndex + 1 == j) {
                            lastIndex = j
                            console.log("lastIndex + 1 === i")
                            continue
                        }
                        this.moveTile(i, j, i, lastIndex + 1)
                        lastIndex++
                        hasMove = true
                    }
                }
            }

        }
        if (hasMove) {
            this.randomNumber()
        }
    }
    /**
     * 上移方法
     */
    moveUp() {
        let hasMove = false
        for (let i = 0; i < GRID_SIZE; i++) {
            let lastIndex = GRID_SIZE - 1
            for (let j = GRID_SIZE - 1; j >= 0; j--) {
                let value = this.tileValue[i][j]
                if (value == 0 || j == lastIndex) {
                    continue
                }
                if (this.tileValue[i][lastIndex] == 0) {
                    this.moveTile(i, j, i, lastIndex)
                    hasMove = true
                } else {
                    if (this.tileValue[i][lastIndex] == value) {
                        this.mergeTile(i, j, i, lastIndex)
                        lastIndex--
                        hasMove = true
                    } else {
                        if (lastIndex - 1 == j) {
                            lastIndex = j
                            continue
                        }
                        this.moveTile(i, j, i, lastIndex - 1)
                        lastIndex--
                        hasMove = true
                    }

                }
            }

        }
        if (hasMove) {
            this.randomNumber()
        }
    }
    /**
     * 移动格子方法,移动到目标位置, 目标位置必须为空
     */

    moveTile(x1: number, y1: number, x2: number, y2: number) {
        this.tiles[x2][y2] = this.tiles[x1][y1];
        this.tiles[x1][y1] = null;
        this.tileValue[x2][y2] = this.tileValue[x1][y1];
        this.tileValue[x1][y1] = 0;
        //调用移动格子动画
        this.tiles[x2][y2].getComponent(Tile).moveTile(x2, y2);
    }

    /**
     * 合并格子方法，先消除旧的两个格子, 然后创建新的格子
     */
    mergeTile(x1: number, y1: number, x2: number, y2: number) {
        let value = this.tileValue[x1][y1]
        //触发销毁缓动和销毁x2节点   
        this.tiles[x2][y2].getComponent(Tile).destroyTile();
        this.tileValue[x2][y2] = 0;
        this.tiles[x2][y2] = null;
        // console.log(" x2已被销毁:", this.tiles[x2][y2], this.tileValue[x2][y2]);
        this.tileValue[x2][y2] = 0;
        //触发移动x1节点缓动，然后再触发销毁缓动，再销毁x1节点
        this.tiles[x1][y1].getComponent(Tile).moveTile(x2, y2);
        this.tiles[x1][y1].getComponent(Tile).destroyTile();
        this.tileValue[x1][y1] = 0;
        this.tiles[x1][y1] = null;
        this.addScore(value * 2);   //添加分数
        //创建新的格子
        this.createTile(value * 2, x2, y2);

        //调用鬼叫
        this.guijiao(value);
    }
    /**
     * 加分与最高分
     */
    addScore(value: number) {
        this.score += value
        if (this.bestScore < this.score) {
            this.bestScore = this.score;
        }
        //更新ui
        this.updateUI()
    }
    /**
     * 更新UI
     */
    updateUI() {
        this.scoreLabel.string = this.score.toString();
        this.bestLabel.string = this.bestScore.toString();
    }
    /**
     * 检查是否结束
     */
    checkGameOver() {
        for (let i = 0; i < GRID_SIZE; i++) {
            for (let j = 0; j < GRID_SIZE; j++) {
                //还有空格子则游戏没结束
                if (this.tileValue[i][j] == 0) {
                    console.log("还有空格子");
                    return false
                } else {
                    //检查每个格子的上方与右方是否有相同的格子，这样就能判断是否还能滑动
                    if (j + 1 < GRID_SIZE && this.tileValue[i][j] == this.tileValue[i][j + 1]) {
                        console.log("还有格子可以滑动");
                        return false
                    }
                    if (i + 1 < GRID_SIZE && this.tileValue[i][j] == this.tileValue[i + 1][j]) {
                        console.log("还有格子可以滑动");
                        return false
                    }
                }

            }
        }
        console.log("没有格子可以滑动了");
        return true
    }
    /**
     * 结束后创建结束ui
     */
    onEnd() {
        console.log("游戏结束");
        let gameover = instantiate(this.gameover);
        this.parentNode.addChild(gameover);
        let script = gameover.getComponent(gameOver);
        script.init(this.score, this.bestScore);
        script.addRestartListener(() => {
            this.restart();
        })
    }
    /**
     * 重新开始方法
     */
    restart() {
        this.score = 0;
        this.reset();
    }

    //---------------------------------------------

    //鬼叫音效
    @property({
        displayName: "gjMusic2",
        type: AudioSource
    })
    gjMusic2: AudioSource = null;
    @property({
        displayName: "gjMusic4",
        type: AudioSource
    })
    gjMusic4: AudioSource = null;
    @property({
        displayName: "gjMusic8",
        type: AudioSource
    })
    gjMusic8: AudioSource = null;
    @property({
        displayName: "gjMusic16",
        type: AudioSource
    })
    gjMusic16: AudioSource = null;
    @property({
        displayName: "gjMusic32",
        type: AudioSource
    })
    gjMusic32: AudioSource = null;
    @property({
        displayName: "gjMusic64",
        type: AudioSource
    })
    gjMusic64: AudioSource = null;
    @property({
        displayName: "gjMusic128",
        type: AudioSource
    })
    gjMusic128: AudioSource = null;
    @property({
        displayName: "gjMusic256",
        type: AudioSource
    })
    gjMusic256: AudioSource = null;
    @property({
        displayName: "gjMusic512",
        type: AudioSource
    })
    gjMusic512: AudioSource = null;
    @property({
        displayName: "gjMusic1024",
        type: AudioSource
    })
    gjMusic1024: AudioSource = null;
    @property({
        displayName: "gjMusic2048",
        type: AudioSource
    })
    gjMusic2048: AudioSource = null;

    guijiao(value: number) {
        if (value === 2) {
            this.gjMusic2.play();
            console.log("gjMusic2 play");
        } else if (value === 4) {
            this.gjMusic4.play();
            console.log("gjMusic4 play");
        } else if (value === 8) {
            this.gjMusic8.play();
            console.log("gjMusic8 play");
        } else if (value === 16) {
            this.gjMusic16.play();
            console.log("gjMusic16 play");
        } else if (value === 32) {
            this.gjMusic32.play();
            console.log("gjMusic32 play");
        } else if (value === 64) {
            this.gjMusic64.play();
            console.log("gjMusic64 play");
        } else if (value === 128) {
            this.gjMusic128.play();
            console.log("gjMusic128 play");
        } else if (value === 256) {
            this.gjMusic256.play();
        } else if (value === 512) {
            this.gjMusic512.play();
        } else if (value === 1024) {
            this.gjMusic1024.play();
        } else if (value === 2048) {
            this.gjMusic2048.play();
        }
    }




}
